---OOSE SoSe 2011 Aufgabe 3
--@author Mickey Reiss <mickeyreiss@gmail.com> (HU:417884)

--kalahaBoard class
--Board to be used for games of Kahala. Ensures that a consistent number
--of seeds remains on the board after each pickUp and drop, assuming no
--third party adds or removes seeds from the board manually.

require"classes"

Class{"KalahaBoard", numPits = Number, numSeeds = Number, board = Table, hand = Number}

---Initialize KalahaBoard
--numPits : number of pits per player
--numSeeds : initial number of seeds per pit
function KalahaBoard:init(numPits, numSeeds)
  self.numPits = numPits or 6
  self.numSeeds = numSeeds or 3

  self.board = {}

  for pit = 1, self.numPits*2+2 do
    self.board[pit] = self.numSeeds
  end
  
  --Empty them pots
  self.board[1] = 0
  self.board[#self.board] = 0

  self:assertEmptyHand()
end

---Pick up all seeds from given pit
--player : 1 or 2
--returns pit index number of next pit
function KalahaBoard:pickUp(player, pit)
  self:assertEmptyHand()
  assert(player == 1 or player == 2)
  local pitIndex = 1+pit+(player-1)*(#self.board/2-1)
  assert(1 < pitIndex and pitIndex < #self.board)
  self.hand = self.board[pitIndex]
  self.board[pitIndex] = 0
  return self:nextPit(pitIndex)
end

---Drop number of seeds from hand into given pit 
--@arg pit : destination by index number
--@arg numSeeds : default 1 seed (-1 means all seeds)
--@returns table with information about new board situation: "next" pit, new total # seeds, pit/player description of target pit
function KalahaBoard:drop(pit, numSeeds)
  if not tonumber(numSeeds) then
    numSeeds = 1
  elseif numSeeds == -1 then
    numSeeds = self.hand
  end
  assert(1 <= pit and pit <= #self.board)
  assert(numSeeds <= self.hand)
  self.board[pit] = self.board[pit] + numSeeds
  self.hand = self.hand - numSeeds
  assert(self.hand >= 0)

  local newplayer
  if pit/7 > 1 then
    newplayer = 2
  else
    newplayer = 1
  end

  return { nextPit = self:nextPit(pit), newTotal = self.board[pit], wasStore = (pit == 1 or pit == #self.board), pit = (((pit-2)%((#self.board-2)/2))+1), player = newplayer }
end

---Find the "next" pit based on clock-wise direction of play
function KalahaBoard:nextPit(pit)
  if pit == #self.board then
    return #self.board/2
  elseif pit == 1 then
    return #self.board/2+1
  elseif pit <= #self.board/2 then
    return pit - 1
  else
    return pit + 1
  end
end

---Returns index of given player's store
--@arg player whose pitIndex is desired
function KalahaBoard:getStoreIndex(player)
  if player == 1 then 
    return 1
  elseif player == 2 then
    return #self.board
  else
    ierror("Get store called with incorrect argument")
  end
end

---returns scores: Player1, Player2
function KalahaBoard:getScores()
  return self.board[self:getStoreIndex(1)], self.board[self:getStoreIndex(2)]
end

---assert that all seeds are on board and that board still has correct number of seeds
--(Checks invariants of the board)
function KalahaBoard:assertEmptyHand()
  assert(self.hand == 0, "Hand is not empty")
  local sum = 0
  for index,pit in pairs(self.board) do
    sum = sum + pit
  end
  assert(sum == 2*self.numPits*self.numSeeds, "Found "..sum.." total seeds, but expected "..2*self.numPits.."*"..self.numSeeds.."="..2*self.numPits*self.numSeeds)
end

---returns the number of seeds in given pit
--@arg player whose seeds to peek at
--@arg pit that's interesting
function KalahaBoard:peek(player, pit)
  assert(player == 1 or player == 2)
  local pitIndex = 1+pit+(player-1)*(#self.board/2-1)
  assert(1 < pitIndex and pitIndex < #self.board)
  return self.board[pitIndex]
end

---Returns kahalaboard as a string for the console
--       1 2 3 4 5 6
--  ----------------------
-- |  0 | Player A   |    |
-- |    | Player B   | 0  |
--  ----------------------
function KalahaBoard:toString()
  local string = "        1  2  3  4  5  6\n"
  string = string.." ----------------------------- \n"
  string = string.."| "..string.format("%02d", self.board[1]).." | "
  for i=2,#self.board/2 do
    string = string..string.format("%02d ", self.board[i])
  end
  string = string.."|    | --Player A\n|    | "
  for i=#self.board/2+1,#self.board-1 do
    string = string..string.format("%02d ", self.board[i])
  end
  string = string.."| "..string.format("%02d ", self.board[#self.board]).."| --Player B\n"

  string = string.." ----------------------------"


    return string
end
